package io.cloud.tec.encryption_algorithm;

import com.google.common.base.Ascii;
import io.cloud.tec.project.enums.RsaKeyType;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import static io.cloud.tec.project.util.RsaUtil.mmapWriteFile;

/**
 * 二进制 binary  以0b或0B开头表示
 * <p>
 * 八进制 octal  以数字0开头表示
 * <p>
 * 十进制 decimal
 * <p>
 * 十六进制 hex 以0x或0X开头表示
 * <p>
 */
class Charsets {

    /**
     * ASCII字符集：主要包括控制字符（回车键、退格、换行键等）；可显示字符（英文大小写字符、阿拉伯数字和西文符号）。
     * <p>
     * ASCII编码：将ASCII字符集转换为计算机可以接受的数字系统的数的规则。使用7位（bits）表示一个字符，共128字符；但是7位编码的字符集只能支持128个字符，为了表示更多的欧洲常用字符对ASCII进行了扩展，ASCII扩展字符集使用8位（bits）表示一个字符，共256字符
     * <p>
     * 0～31 及 127(共 33 个)是控制字符或通信专用字符（其余为可显示字符），如控制符：LF（换 行）、CR（回车）、FF（换页）、DEL（删除）、BS（退格)
     * 32～126(共 95 个)是字符(32 是空格），其中 48～57 为 0 到 9 十个阿拉伯数字。
     * 65～90 为 26 个大写英文字母，97～122 号为 26 个小写英文字母，其余为一些标点符号、 运算符号等。
     * 后 128 个称为扩展 ASCII 码。许多基于 x86 的系统都支持使用扩展（或“高”）ASCII。扩展 ASCII 码允许将每个字符的第 8 位用于确定附加的 128 个特殊符号字符、外来语字母和图 形符号。
     * <p>
     * ASCII的最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号，因此只能用于显示现代美国英语（而且在处理英语当中的外来词如naïve、café、élite等等时，所有重音符号都不得不去掉，即使这样做会违反拼写规则）。而EASCII虽然解决了部份西欧语言的显示问题，但对更多其他语言依然无能为力。因此现在的苹果电脑已经抛弃ASCII而转用Unicode。
     */
    @Test
    /**
     * TODO 怎么输出ASCII编码、EASCII编码的全部字符
     * -Dfile.encoding=us-ascii
     */
    void ASCIITest() throws IOException {
//        //        for (int i = 0; i < (1 << 8); i++) {
////        for (char i =  '\u0000'; i < '\u0100'; i++) {
////        for (char i =  '\u0000'; i <= '\u00ff'; i++) {
//        for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
//            System.out.println((int) i + ":" + i);
//        }
        String file = "EASCII.txt";

        final RandomAccessFile randomAccessFile = new RandomAccessFile(new File(file), "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();

        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 256*2);

        for (int i = 0; i <= 255; i++) {
            mappedByteBuffer.put(charToBytes(new char[] {(char)i}));
        }
        fileChannel.close();
        randomAccessFile.close();
    }

    // char转byte
    public static byte[] charToBytes(char[] chars) {
        Charset charset = StandardCharsets.UTF_8;
        CharBuffer charBuffer = CharBuffer.allocate(chars.length);
        charBuffer.put(chars);
        charBuffer.flip();
        ByteBuffer byteBuffer = charset.encode(charBuffer);
        return byteBuffer.array();
    }


    /**
     * GB2312使用 1-2 个字节,把那些127号之后的奇异符号们（即EASCII）取消掉，规定：一个小于127的字符的意义与原来相同，但两个大于127的字符连在一起时，就表示一个汉字，前面的一个字节（他称之为高字节）从0xA1用到 0xF7，后面一个字节（低字节）从0xA1到0xFE，这样我们就可以组合出大约7000多个简体汉字了。
     * GB2312或GB2312-80是中国国家标准简体中文字符集，全称《信息交换用汉字编码字符集·基本集》，又称GB0，由中国国家标准总局发布，1981年5月1日实施。
     * 对于人名、古汉语等方面出现的罕用字，GB2312不能处理，这导致了后来GBK及GB 18030汉字字符集的出现。
     * <p>
     * 微软利用GB 2312-80未使用的编码空间，收录GB 13000.1-93全部字符制定了GBK编码。
     * 根据微软资料，GBK是对GB2312-80的扩展，也就是CP936字码表 (Code Page 936)的扩展（之前CP936和GB 2312-80一模一样），最早实现于Windows 95简体中文版。
     * 虽然GBK收录GB 13000.1-93的全部字符，但编码方式并不相同。
     * GBK自身并非国家标准，只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为"技术规范指导性文件"。
     */
    @Test
    void GB2312Test() {
        // 0111 1111
        // 0x7F
        System.out.println(Integer.toHexString(127));
        //  0x80
        System.out.println(Integer.toHexString(128));

    }

    /**
     * Unicode 字符集涵盖了目前人类使用的所有字符，并为每个字符进行统一编号，分配唯一的字 符码（Code Point）。
     * Unicode 字符集将所有字符按照使用上的频繁度划分为 17 个层面（Plane）， 每个层面上有 2 16=65536 个字符码空间。
     * 其中第 0 个层面 BMP，基本涵盖了当今世界用到的所有字符。其他的层面要么是用来表示一 些远古时期的文字，要么是留作扩展。
     * <p>
     * Unicode是字符集，UTF-32/ UTF-16/ UTF-8是三种字符编码方案。
     * <p>
     * 这意味着字符U+4E2D在UTF-16编码方式下可能被保存为4E 2D或者2D 4E，这取决于该系统使用的是大尾端(big-endian)还是小尾端(little-endian)。
     * <p>
     * 为了解决这个问题，多字节的Unicode编码方式定义了一个"字节顺序标记(Byte Order Mark)"-BOM，它是一个特殊的非打印字符，你可以把它包含在文档的开头来指示你所使用的字节顺序。
     * <p>
     * UTF编码	Byte Order Mark(BOM)
     * UTF-8 without BOM	无
     * UTF-8 with BOM	EF BB BF
     * UTF-16(BE)大端	FF FE
     * UTF-16(LE)大端	FE FF
     * UTF-32(BE)大端	FF FE 00 00
     * UTF-32(LE)大端	00 00 FE FF
     * <p>
     * UTF-8（8-bit Unicode Transformation Format）
     * UTF-8使用一至四个字节为每个字符编码：
     * <p>
     * 128个US-ASCII字符只需一个字节编码（Unicode范围由U+0000至U+007F）。
     * 2.带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要二个字节编码（Unicode范围由U+0080至U+07FF）。
     * 其他基本多文种平面（BMP）中的字符（这包含了大部分常用字）使用三个字节编码。
     * 其他极少使用的Unicode辅助平面的字符使用四字节编码。
     * ANSI编码，通常指的是平台的默认编码， 例如英文操作系统中是ISO-8859-1，中文系 统是GBK
     */
    @Test
    void UnicodeTest() {
        System.out.println(Integer.valueOf(0x10FFFF));
        System.out.println(Integer.valueOf(0x010000));
        System.out.println(Integer.valueOf(0x0FFFFF));


//        System.out.println(Integer.valueOf(0xD800   1101 1000 0000 0000));
//        System.out.println(Integer.valueOf(0xDC00   1101 1100 0000 0000));
    }


    @Test
    void StringTest() {
        int num = 256;
        System.out.println(String.format("%d", num));
        System.out.println(String.format("%x", num));
        System.out.println(String.format("%o", num));
        System.out.println(Integer.toString(num));
// 将数字转换成二进制
        System.out.println(Integer.toBinaryString(num));
// 将数字转换成十六进制
        System.out.println(Integer.toHexString(num));
// 将数字转换成八进制
        System.out.println(Integer.toOctalString(num));
        System.out.println(Integer.toString(num,2));
        System.out.println(Integer.toString(num,8));
        System.out.println(Integer.toString(num,10));
        System.out.println(Integer.toString(num,16));
    }
}
